package org.edgegallery.developer.service.virtual.create;

import java.io.File;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;
import org.edgegallery.developer.mapper.ProjectMapper;
import org.edgegallery.developer.model.vm.NetworkInfo;
import org.edgegallery.developer.model.vm.VmCreateConfig;
import org.edgegallery.developer.model.vm.VmInstantiateInfo;
import org.edgegallery.developer.model.workspace.ApplicationProject;
import org.edgegallery.developer.model.workspace.EnumTestConfigStatus;
import org.edgegallery.developer.service.ProjectService;
import org.edgegallery.developer.service.virtual.VmService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;

@Service("vm_distributeInfo_service")
public class VmStageDistribute implements VmCreateStage{
    private static final Logger LOGGER = LoggerFactory.getLogger(VmStageInstantiate.class);

    /**
     * the max time for wait workStatus.
     */
    private static final Long MAX_SECONDS = 3600L;

    /**
     * image package upload  workStatus:fail.
     */
    private static final String PACKAGE_FAIL = "killed";
    /**
     * image package upload  workStatus:success.
     */
    private static final String PACKAGE_SUCCESS = "killed";

    @Autowired
    private ProjectMapper projectMapper;

    @Autowired
    private ProjectService projectService;

    @Autowired
    private VmService vmService;

    @Override
    public boolean execute(VmCreateConfig config) throws InterruptedException {
        boolean processSuccess = false;
        EnumTestConfigStatus distributeStatus = EnumTestConfigStatus.Failed;
        ApplicationProject project = projectMapper.getProjectById(config.getProjectId());
        String userId = project.getUserId();
        // deploy app
        File csar = new File(projectService.getProjectPath(config.getProjectId()) + config.getAppInstanceId() + ".csar");

        String distributeResult = vmService.distributeVmToAppLcm(csar, project, config, userId, config.getLcmToken());
        if (distributeResult==null) {
            LOGGER.error("Failed to create vm which packageId is : {}.", config.getPackageId());
        } else {
            JsonObject jsonObject = new JsonParser().parse(distributeResult).getAsJsonObject();
            JsonElement status = jsonObject.get("status");
            if (PACKAGE_FAIL.equals(status.getAsString())) {
                LOGGER.error("Failed to upload vm image packageId is : {}.", config.getPackageId());
            } else if (PACKAGE_SUCCESS.equals(status.getAsString())){
                processSuccess = true;
                distributeStatus = EnumTestConfigStatus.Success;
                config.setLog("vm instantiate success");
            }else {
                // compare time between now and deployDate
                long time = System.currentTimeMillis() - config.getCreateTime().getTime();
                LOGGER.info("over time:{}, wait max time:{}, start time:{}", time, MAX_SECONDS,
                    config.getCreateTime().getTime());
                if (config.getCreateTime() == null || time > MAX_SECONDS * 1000) {
                    config.setLog("Failed to get create vm result ");
                    String message = "Failed to get create vm result after wait {} seconds which appInstanceId is : {}";
                    LOGGER.error(message, MAX_SECONDS, config.getAppInstanceId());
                } else {
                    return true;
                }
            }
        }
        vmService.updateCreateVmResult(config, project, "distributeInfo", distributeStatus);
        LOGGER.info("update config result:{}", config.getStatus());
        return processSuccess;
    }

    @Override
    public boolean destroy() {
        return true;
    }

    @Override
    public boolean immediateExecute(VmCreateConfig config) {
        return true;
    }

}
